package com.gjy.design.single;

import java.io.Serializable;

/**
 * @author gjy
 * @version 1.0
 * @since 2025-11-06 10:06:38
 */
public class DCLSingleton implements Serializable {

    private static final long serialVersionUID = -5094510330356402727L;

    // volatile 关键字确保了多线程下的可见性和有序性，防止指令重排
    // instance = new DCLSingleton() 这一步并非原子操作，可能被重排：
    // 1. 分配内存空间 2. 初始化对象 3. 将 instance 引用指向分配的内存
    // 如果发生重排为 1->3->2，线程A执行到3，但未初始化，线程B此时判断 instance 不为 null，直接返回了一个未初始化的对象。
    private static volatile DCLSingleton instance;

    private DCLSingleton() {
        // 防御反射攻击
        if (instance != null) {
            throw new RuntimeException("不允许通过反射创建实例");
        }
    }

    public static DCLSingleton getInstance() {
        // 第一次检查，如果实例已存在，直接返回，无需进入同步块，提高性能
        if (instance == null) {
            // 对类对象加锁，确保只有一个线程能进入
            synchronized (DCLSingleton.class) {
                // 第二次检查，防止多个线程同时通过第一次检查后，在锁外排队等待，
                // 当锁释放后，如果没有第二次检查，它们会依次创建实例。
                if (instance == null) {
                    instance = new DCLSingleton();
                }
            }
        }
        return instance;
    }

    /**
     * 防御序列化破坏的关键方法
     * 在反序列化时，JVM会调用这个方法，而不是直接使用新创建的对象。
     * 这样就能保证返回的是同一个单例实例。
     *
     * @return 唯一的单例实例
     */
    private Object readResolve() {
        return getInstance();
    }

    public void doSomething() {
        System.out.println("双重检查锁单例正在执行业务...");
    }

}
